package easy.trace.agent.plugin;

import easy.trace.agent.define.Instrumentation;
import easy.trace.agent.log4j.ConfigurationAppender;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author easy
 */
public class AgentBuilder implements ClassFileTransformer {

    private List<PluginDefine.OfficialComponent> officialPlugins;
    private AtomicBoolean firstStart;
    private PluginFinder pluginFinder;
    private ConfigurationAppender configurationAppender;

    public AgentBuilder() {
        this.pluginFinder = new PluginFinder(t -> {
            System.out.println("插件载入异常:" + t.getLocalizedMessage());
        });
        this.configurationAppender = new ConfigurationAppender(t -> {
            System.out.println("log4j文件追加异常:" + t.getLocalizedMessage());
        });
        this.firstStart = new AtomicBoolean(true);
    }

    /**
     * 初始化功能插件
     *
     * @return
     */
    public AgentBuilder Default() {
        try {
            pluginFinder.loadPlugin();
            this.officialPlugins = pluginFinder.getPlugins();
            System.out.println("--------------- 插件载入:" + this.officialPlugins.size() + " ---------------");
            if (officialPlugins != null && !officialPlugins.isEmpty()) {
                boolean appendable = this.configurationAppender.compareAndAppend();
                System.out.println("--------------- log4j文件追加:" + (appendable ? "成功" : "失败") + " ---------------");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this;
    }

    /**
     * 类织入扩展点
     *
     * @param loader
     * @param className
     * @param classBeingRedefined
     * @param protectionDomain
     * @param classfileBuffer
     * @return
     * @throws IllegalClassFormatException
     */
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        if (officialPlugins == null || officialPlugins.isEmpty()) {
            return null;
        }
        waitOneSeconds();

        return officialPlugins.stream()
                .map(PluginDefine.OfficialComponent::getInstrumentation)
                .filter(instrument -> Optional.ofNullable(instrument).isPresent())
                .filter(instrument -> instrument.check(className))
                .findFirst()
                .map(Instrumentation::interceptPoints)
                .orElse(null);
    }

    /**
     * 追加等待
     */
    private void waitOneSeconds() {
        if (firstStart.get()) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            firstStart.set(false);
        }
    }
}
